from __future__ import division
from functools import partial
from progress import ProgressDisplay
from osm_utils import *
from problem_generator import *
from map_problem import *
from search_runners import *
from cool import *

'''
Created on 11/11/2013

@author: Lior Friedman
'''



'''Note: you may change the signatures of the RunExperiment methods, as long as you update main accordingly'''


def RunMeasuredSearch(map, initial_key, goal_key, search_runner, *args):
    node, developed_nodes_count, run_time, path_cost = search_runner(map, initial_key, goal_key, *args)
    assert node is not None
    return developed_nodes_count, run_time, path_cost

def RunExperiment1(map, problem_set, output_file):
    '''You must implement this function.
     Runs experiment 1 as written in the report'''

    for (initial_key, goal_key) in ProgressDisplay(problem_set):
        output_file.write('{}, {}'.format(initial_key, goal_key))

        nodes, run_time, route_cost = RunMeasuredSearch(map, initial_key, goal_key, RunAstar, C_c, H_c)
        output_file.write(', {}, {}, {}'.format(nodes, run_time, route_cost))

        nodes, run_time, route_cost = RunMeasuredSearch(map, initial_key, goal_key, RunAstar, C_f, H_f)
        output_file.write(', {}, {}, {}'.format(nodes, run_time, route_cost))

        nodes, run_time, route_cost = RunMeasuredSearch(map, initial_key, goal_key, RunSigmaAstar, (0.4, 0.4))
        output_file.write(', {}, {}, {}'.format(nodes, run_time, route_cost))

        output_file.write('\n')


def RunExperiment2(map, problem_set, output_file, problems_num = 10):
    '''You must implement this function.
     Runs experiment 2 as written in the report'''
    
    sigma_weights = (0.4, 0.4)
    C_sigma_p = partial(C_sigma, *sigma_weights)
    H_sigma_p = partial(H_sigma, *sigma_weights)

    experiments_weights = [x / 10 for x in xrange(0, 10)] # = [0,0.1 .. 0.9]. xrange accepts only integer step, but we need decimal float

    for (initial_key, goal_key) in ProgressDisplay(list(problem_set)[:problems_num]):
        output_file.write('{}, {}'.format(initial_key, goal_key))
        for weight in experiments_weights:
            nodes, run_time, route_cost = RunMeasuredSearch(map, initial_key, goal_key, RunWeightedAstar, C_sigma_p, H_sigma_p, weight)
            output_file.write(', {}, {}, {}, {}'.format(weight, nodes, run_time, route_cost))
        output_file.write('\n')

def RunExperiment3(map, problem_set, output_file):
    '''You must implement this function.
     Runs experiment 3 as written in the report'''
    
    for (initial_key, goal_key) in ProgressDisplay(list(problem_set)):
        output_file.write('{}, {}'.format(initial_key, goal_key))
        node, nodes, run_time, route_cost, Cf = RunCoolPathSearch(map, initial_key, goal_key)
        path_time = sum(n.action.CalcTime() for n in node.path() if n.action)
        output_file.write(', {}, {}, {}, {}, {}'.format(nodes, run_time, Cf, path_time, route_cost))
        output_file.write('\n')


if __name__ == '__main__':
    '''Main part. You may add to this, if you wish'''
    map = CountryMap().LoadMap()
    problem_set = LoadfFromFile('ProblemSet100.csv')
    RunExperiment1(map, problem_set, open('output1.csv', 'w'))
    RunExperiment2(map, problem_set, open('output2.csv', 'w'))

    problem_set = [(108838, 111600), (558885, 598178), (205999, 178412), (623958, 69307), (291798, 259272), (384151, 397099), (377949, 370520), (175388, 197666), (560629, 553937), (525187, 68288)]
    RunExperiment3(map, problem_set, open('output3.csv', 'w'))